package com.esdk.utils;

import com.esdk.exception.SdkRuntimeException;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Getter映射
 * 类似于mp那种User::getId的实现
 * @param <T>
 */
@FunctionalInterface
public interface FieldGetter<T> extends Serializable {

    Object getter(T t);
    
    default String getTargetField(){
        return getSignature().field;
    }
    
    default Class<T> getTargetClass(){
        return (Class<T>)getSignature().clazz;
    }
    
    private GetterSignature getSignature(){
        return Cache.DATA.computeIfAbsent(this.getClass(), (clazz) -> {
            try {
                Method writeReplace = clazz.getDeclaredMethod("writeReplace");
                writeReplace.setAccessible(true);
                SerializedLambda lambdaInfo = (SerializedLambda)writeReplace.invoke(FieldGetter.this);
                return new GetterSignature(lambdaInfo.getImplClass().replace("/", "."), lambdaInfo.getImplMethodName());
            } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | ClassNotFoundException e) {
                throw new SdkRuntimeException("lambda getter获取失败", e);
            }
        });
    }

    /**
     * lambda解析缓存
     */
    class Cache{
        private static final ConcurrentHashMap<Class<? extends FieldGetter>, GetterSignature> DATA = new ConcurrentHashMap<>();
    }

    /**
     * Getter签名结构体
     */
    class GetterSignature{
        private String field;
        private Class<?> clazz;
        private GetterSignature(String className, String getterMethod) throws ClassNotFoundException {
            this.clazz = Class.forName(className);
            if(getterMethod.startsWith("get")){
                this.field = Character.toLowerCase(getterMethod.charAt(3)) + getterMethod.substring(4);
            }else{
                this.field = getterMethod;
            }
        }
    }

}
